#ifndef _NE_IMAGE_H_
#define _NE_IMAGE_H_

#include <mathematics/Color.h>
#include <system/Resource.h>
#include <graphics/RenderSystemDefine.h>

namespace ne
{
    class NEAPI Image : public Resource
    {
        public:
            Image(ResourceManager *pManager,
                  const uint64_t id,
                  const std::string &name,
                  const std::string &fileName,
                  const bool isManual,
                  ManualResourceLoader *pLoader);

            // Create Image and new memory
            void createInternalImage(const uint32_t width, const uint32_t height, const uint32_t depth, const PixelFormat format, const PixelType pt=PT_UNSIGNED_BYTE);

            void freeInternalImage();

            // Load data, delete the old memory and new memory
            void loadData(const void *data, const uint32_t width, const uint32_t height, const uint32_t depth, const PixelFormat format, const PixelType pt=PT_UNSIGNED_BYTE);

            uint32_t getWidth() const;

            uint32_t getHeight() const;

            uint32_t getDepth() const;

            // Bits Per Pixel Base Data
            uint32_t getBPPBD() const;

            // Bits Per Pixel
            uint32_t getBPP() const;

            uint32_t getPixelSize() const;

            PixelFormat getFormat() const;

            PixelType getPixelType() const;

            Color getColorAt(const uint32_t x, const uint32_t y=0, const uint32_t z=0) const;

            bool hasAlpha() const;

            byte* getData(const uint32_t z=0);

            const byte* getData(const uint32_t z=0) const;

            virtual ~Image();

        public:
            static uint32_t GetPixelSize(const PixelFormat format, const PixelType pt);

        protected:
            virtual bool loadImplement();

            virtual bool unloadImplement();

            virtual bool downloadImplement();

            virtual size_t _calculateSize() const;

        private:
            uint32_t mWidth;
            uint32_t mHeight;
            uint32_t mDepth;
            PixelFormat mFormat;
            PixelType mPixelType;
            byte *mpData;
    };

    class NEAPI ImagePtr : public SharedPtr<Image>
    {
        public:
            ImagePtr() : SharedPtr<Image>() {}
            explicit ImagePtr(Image *pImage) : SharedPtr<Image>(pImage) {}
            ImagePtr(const ImagePtr &pImage) : SharedPtr<Image>(pImage) {}

            ImagePtr(const ResourcePtr &p)
                : SharedPtr<Image>()
            {
                mpPtr = static_cast<Image*>(p.ptr());
                mpUseCount = p.getUseCountPtr();
                if (mpUseCount)
                {
                    ++(*mpUseCount);
                }
            }

            ImagePtr& operator = (const ResourcePtr &p)
            {
                if (mpPtr == static_cast<Image*>(p.ptr()))
                {
                    return *this;
                }
                ImagePtr temp(p);
                swap(temp);
                return *this;
            }
    };
}
#endif

